// ServiceControl.cs
//

namespace ServiceAdmin
{
    using System;
    using System.ComponentModel;
    using System.ServiceProcess;
    using System.Windows.Forms;

	public delegate void ServiceErrorEvent(ServiceControl sender, int errorNumber);
	public delegate void ServiceStatusChangeEvent(ServiceControl sender, ServiceControllerStatus status);

    /// <summary>
    /// Summary description for ServiceControl.
    /// </summary>
    public class ServiceControl
    {
        public  event   ServiceStatusChangeEvent	OnStatusChange;
		public	event	ServiceErrorEvent			OnError;

        private ServiceController					_service		= null;
        private ServiceControllerStatus				_status			= ServiceControllerStatus.Stopped;
        private Timer								_statusTimer	= new Timer();

		private bool								_errorOccured	= false;
		private bool								_restartService	= false;


		public bool ErrorOccured
		{
			get { return _errorOccured; }
		}

        public ServiceControllerStatus Status
        {
            get { return _status; }
        }


        /// <summary>
        /// throws exception number 100001 - service is not installed
        /// </summary>
        public ServiceControl(int timer, string serviceName, string machineName)
        {
            try
            {
				if (machineName == String.Empty || machineName == null || machineName.ToLower() == "local")
				{
					_service = new ServiceController(serviceName);
				}
				else
				{
					_service = new ServiceController(serviceName, machineName);
				}
            }
            catch
            {
				FireError(100001);
            }

            _statusTimer.Interval = timer;
            _statusTimer.Tick += OnTimedEvent;
            _statusTimer.Enabled = true;
        }


		/// <summary>
		/// throws exception number 100002 - service is not ready
		/// </summary>
		public void StartTimer()
		{
			_status = GetStatus();

			FireEvent(null);
			_statusTimer.Start();
		}


        public void Start()
        {
			_service.Refresh();

			if (GetStatus().Equals(ServiceControllerStatus.Stopped))
			{
				OnStatusChange(this, ServiceControllerStatus.ContinuePending);
				_service.Start();
			}
        }


        public void Stop()
        {
			_service.Refresh();

			if (GetStatus().Equals(ServiceControllerStatus.Running))
			{
				OnStatusChange(this, ServiceControllerStatus.ContinuePending);
				StopServices(_service);
			}
        }


        public void Restart()
        {
			if (!_restartService)
			{
				Stop();
				_restartService = true;
			}
        }


        private void StopServices(ServiceController service)
        {
            for (int i = 0; i < service.DependentServices.Length; ++i)
            {
                ServiceController currentService = service.ServicesDependedOn.GetValue(i) as ServiceController;

                if (currentService.CanStop)
                {
                    StopServices(currentService);
                }
            }
            service.Stop();
        }


        /// <summary>
        /// throws exception number 100002 - service is not ready
        /// </summary>
        private void OnTimedEvent(object source, EventArgs e)
        {
			if (GetStatus() != _status)
            {
                _status = GetStatus();
                FireEvent(e);
            }
        }


        private void FireEvent(EventArgs e)
        {
            if (OnStatusChange != null)
            {
				if (_restartService)
				{
					_restartService = false;
					Start();
				}
				else
				{
					OnStatusChange(this, GetStatus());
				}
            }
        }


		private void FireError(int exceptionNumber)
		{
			if (OnError != null)
			{
				_errorOccured = true;
				_statusTimer.Stop();

				OnError(this, exceptionNumber);
			}
		}


		private ServiceControllerStatus GetStatus()
		{
			try
			{
				_service.Refresh();
				return _service.Status;
			}
			catch
			{
				FireError(100002);
			}
			return ServiceControllerStatus.ContinuePending;
		}
    }
}